﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Drawing;
using System.Reflection;
using System.Diagnostics;
using Fiddler;
using System.IO;
using System.Text;
using RazorEngine;
using System.Net;

namespace MinecraftBrowserLaunch
{
    public static class Program
    {
        static NotifyIcon NotifyIcon;
        static ContextMenuStrip ContextMenu;

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            if (!File.Exists("minecraft.jar"))
            {
                WebClient c = new WebClient();
                c.DownloadFile("https://s3.amazonaws.com/MinecraftDownload/launcher/minecraft.jar", "minecraft.jar");
            }

            Razor.DefaultTemplateService.Namespaces.Add("LibMinecraft.Model");

            ContentTypes = new Dictionary<string, string>();
            ContentTypes.Add(".html", "text/html");
            ContentTypes.Add(".css", "text/css");
            ContentTypes.Add(".jpg", "image/jpeg");
            ContentTypes.Add(".jpeg", "image/jpeg");
            ContentTypes.Add(".png", "image/png");

            NotifyIcon = new NotifyIcon();
            NotifyIcon.Text = "Minecraft Web Launcher";
            NotifyIcon.Icon = Icon.ExtractAssociatedIcon(AppDomain.CurrentDomain.FriendlyName);
            NotifyIcon.Visible = true;

            ContextMenu = new ContextMenuStrip();
            ContextMenu.Items.Add(new ToolStripMenuItem("Exit"));
            ContextMenu.Items[0].Click += new EventHandler(Exit_Clicked);

            NotifyIcon.ContextMenuStrip = ContextMenu;

            FiddlerApplication.BeforeRequest += new SessionStateHandler(FiddlerApplication_BeforeRequest);
            FiddlerApplication.BeforeResponse += new SessionStateHandler(FiddlerApplication_BeforeResponse);
            FiddlerApplication.Startup(8877, true, true);

            Application.Run();
        }

        static Dictionary<string, string> ContentTypes;

        static void FiddlerApplication_BeforeResponse(Session oSession)
        {
            Console.WriteLine(oSession.fullUrl);
            if (oSession.hostname == "launch.minecraft.net")
            {
                // Check for a suitable replacement
                Uri uri = new Uri(oSession.fullUrl);
                byte[] file = GetFile(uri.LocalPath);
                if (file == null)
                    return;
                if (uri.LocalPath.EndsWith(".html"))
                {
                    StreamReader sr = new StreamReader(new MemoryStream(file));
                    string template = sr.ReadToEnd();
                    sr.Close();
                    if (template == null)
                        return;
                    try
                    {
                        template = Razor.Parse(template, new PageModel(uri, ParseQuery(uri.Query)));
                    }
                    catch (Exception e)
                    {
                        template = e.Message;
                    }

                    if (ContentTypes.ContainsKey(Path.GetExtension(uri.LocalPath)))
                        oSession.oResponse.headers["Content-Type"] = ContentTypes[Path.GetExtension(uri.LocalPath)];
                    oSession.responseCode = 200;
                    oSession.utilSetResponseBody(template);
                    return;
                }
                if (ContentTypes.ContainsKey(Path.GetExtension(uri.LocalPath)))
                    oSession.oResponse.headers["Content-Type"] = ContentTypes[Path.GetExtension(uri.LocalPath)];
                oSession.responseCode = 200;
                oSession.ResponseBody = file;
            }
        }

        static void FiddlerApplication_BeforeRequest(Session oSession)
        {
            oSession.bBufferResponse = true;
            if (oSession.hostname == "launch.minecraft.net")
            {
                if (oSession.HTTPMethodIs("POST"))
                {
                    if (oSession.oRequest.headers["Content-Type"] == "application/x-www-form-urlencoded")
                    {
                        Uri url = new Uri(oSession.fullUrl);
                        if (url.LocalPath == "/launch.html")
                        {
                            oSession.utilDecodeRequest();
                            StreamReader sr = new StreamReader(new MemoryStream(oSession.RequestBody));
                            string request = sr.ReadToEnd();
                            sr.Close();
                            LaunchMinecraft(ParseQuery(request));
                        }
                    }
                }
            }
        }

        public static void LaunchMinecraft(Dictionary<string, string> Query)
        {
            if (Query.ContainsKey("server"))
            {
                Process.Start("javaw", "-cp Minecraft.jar net.minecraft.LauncherFrame " + Query["username"] + " " +
                    Query["password"] + " " + Query["server"]);
            }
            else
            {
                Process.Start("javaw", "-cp Minecraft.jar net.minecraft.LauncherFrame " + Query["username"] + " " +
                    Query["password"]);
            }
        }

        public struct PageModel
        {
            public Uri Url;
            public Dictionary<string, string> Query;

            public PageModel(Uri Url, Dictionary<string, string> Query)
            {
                this.Url = Url;
                this.Query = Query;
            }
        }

        private static Dictionary<string, string> ParseQuery(string p)
        {
            if (p.StartsWith("?"))
                p = p.Substring(1);
            Dictionary<string, string> queryValues = new Dictionary<string, string>();
            foreach (string s in p.Split('&'))
            {
                if (string.IsNullOrWhiteSpace(s))
                    continue;
                if (s.Contains("="))
                {
                    queryValues.Add(s.Split('=')[0].ToLower(),
                        Uri.UnescapeDataString(s.Split('=')[1]));
                }
                else
                    queryValues.Add(s.ToLower(), null);
            }
            return queryValues;
        }

        static byte[] GetFile(string File)
        {
            try
            {
                File = File.Replace("/", ".");
                byte[] b;
                Stream s = Assembly.GetExecutingAssembly().GetManifestResourceStream("MinecraftBrowserLaunch.EmbeddedWeb" + File);
                b = new byte[s.Length];
                s.Read(b, 0, (int)s.Length);
                return b;
            }
            catch { return null; }
        }

        static void Exit_Clicked(object sender, EventArgs e)
        {
            NotifyIcon.Dispose();
            ContextMenu.Dispose();
            FiddlerApplication.Shutdown();
            Application.Exit();
        }
    }
}
